from datetime import datetime, timezone
from typing import Optional
import logging
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal_with,reqparse
from configs import app_config
from controllers.errors.error import AccountBannedError, HTTPNotLoginError, WeChatLoginParameterError
from core.entities.account_role import AccountRole
from libs.helper import extract_remote_ip, gender_value
from libs.login import login_required
from models.account import Account, AccountStatus, Tenant
from controllers.mini_app import api
from services.account_service import AccountService, TenantService
from extensions.ext_database import db
from libs.mini_wechat_oauth import WeChatMiniAppOAuth
from services.errors.tenant import TenantNotFoundError
from services.wechat_info_service import WeChatAppType, WeChatConfigService
from fields.account_fields import account_with_role_fields
def _get_account_by_openid_or_email(provider: str, open_id: str|None, email: str|None = None) -> Optional[Account]:
    """
    Get account by openid or email.
    """
    account = None
    try:
        if open_id:
            account = Account.get_by_openid(provider, open_id)
            if account:
                account.open_id = open_id
        if not account and email:
            account = db.session.query(Account).filter_by(email=email).one_or_none()
        
        if not account:
            return None
    except:
        logging.error(f"Failed to get account by openid: {open_id}")
    return account


class WeChatAPPLoginApi(Resource):
    _provider = 'wechat_app'

    # 登录
    def get(self,code: str):
        wechat_app_id = request.headers.get('wechatappid')
        tenant_id = request.headers.get('tenantid')
        if not tenant_id or not wechat_app_id:
            raise WeChatLoginParameterError()
        WeChatConfigService.get_wechat_tenant_info(tenant_id,wechat_app_id,WeChatAppType.WECHAT_MINI_APP)
        tokenDict = WeChatMiniAppOAuth.get_access_token(
            tenant_id, wechat_app_id, code)
        openid = tokenDict['openid']

        account = _get_account_by_openid_or_email(self._provider, openid)
        if account:
            if account.status == AccountStatus.BANNED.value or account.status == AccountStatus.CLOSED.value:
                return {'error': 'Account is banned or closed.'}, 403
            if account.status == AccountStatus.PENDING.value:
                account.status = AccountStatus.ACTIVE.value
                account.initialized_at = datetime.now(
                    timezone.utc).replace(tzinfo=None)
                db.session.commit()
            
            AccountService.update_login_info(account,ip_address=extract_remote_ip(request))
            token = AccountService.get_account_jwt_token(account,tenant_id,open_id=openid)
            role,isOwner = TenantService.is_owner(account.id,tenant_id)
            return {'result': 'success', 'data': token,'role':role, 'isOwner': isOwner,"interface_language":account.interface_language}, 200
        # tokenDict['account_id'] = account_id

        # else:
        #     account = RegisterService.register(user_info.email, user_info.name, open_id=openid, provider=self._provider)
        #     account_id = account.id
        #     tokenDict['account_id'] = account_id
        return {'result': 'failed'}, 403


class WeChatAPPRegisterApi(Resource):
    _provider = 'wechat_app'
    # 这个方法是注册用户

    def get(self, code:str, phoneCode: str,):
        wechat_app_id = request.headers.get('wechatappid')
        tenant_id = request.headers.get('tenantid')
        if not wechat_app_id or not tenant_id:
            raise WeChatLoginParameterError()
        tokenDict = WeChatMiniAppOAuth.get_access_token(
            tenant_id, wechat_app_id, code)
        openid = tokenDict['openid']
        phonDict = WeChatMiniAppOAuth.get_phon_no(
            tenant_id, wechat_app_id, phoneCode, openid)
        purePhoneNumber = phonDict['purePhoneNumber']
        account = _get_account_by_openid_or_email(self._provider, openid)
        if not account:
            # return {'msg': '该手机号已注册，请直接登录'}, 400
        # else:
            email = f"{purePhoneNumber}{app_config.ACCOUNT_EMAIL_SUFFIX}"
            account = _get_account_by_openid_or_email(
                provider=self._provider, open_id=None, email=email)
            if not account:
                # account = RegisterService.register(email, purePhoneNumber, open_id=purePhoneNumber, provider=self._provider)
                account = AccountService.create_account(
                    email=email,phone=purePhoneNumber,name=purePhoneNumber, interface_language='zh-CN',password=f"qwer{purePhoneNumber[4:]}", interface_theme='light',force=True)

            AccountService.link_account_integrate(
                self._provider, openid, account)
            role, isCreater = TenantService.is_owner(account.id,tenant_id)
            if not isCreater:
                tenant = db.session.query(Tenant).filter(
                    Tenant.id == tenant_id).first()
                if not tenant:
                    raise TenantNotFoundError()
                TenantService.create_tenant_member(
                    tenant=tenant, account=account,role=AccountRole.AGENT_USER.value)

        if not account:
            return {'result': 'failed'}, 401
        if account.status == AccountStatus.BANNED.value or account.status == AccountStatus.CLOSED.value:
            raise AccountBannedError()
        if account.status == AccountStatus.PENDING.value:
            account.status = AccountStatus.ACTIVE.value
            account.initialized_at = datetime.now(
                timezone.utc).replace(tzinfo=None)
            db.session.commit()

        AccountService.update_login_info(account,ip_address=extract_remote_ip(request))
        token = AccountService.get_account_jwt_token(account,tenant_id,open_id=openid)
        role,isOwner = TenantService.is_owner(account.id,tenant_id)
        return {'result': 'success', 'data': token,'role':role, 'isOwner': isOwner}, 200

class PersonalInfoApi(Resource):
    @login_required
    @marshal_with(account_with_role_fields)
    def get(self):
        account = current_user
        if not isinstance(account,Account):
            raise HTTPNotLoginError()
        return account
    
    @login_required
    @marshal_with(account_with_role_fields)
    def post(self):
        account = current_user
        if not isinstance(account,Account):
            raise HTTPNotLoginError()
        parser = reqparse.RequestParser()
        parser.add_argument("name",type=str,required=True,nullable=False,location="json")
        parser.add_argument("avatar",type=str,required=True,nullable=False,location="json")
        parser.add_argument("gender",type=gender_value,required=True,nullable=False,location="json")
        args = parser.parse_args()
        AccountService.update_account(account,**args)
        return account

api.add_resource(WeChatAPPLoginApi, '/wechat_app/login/<string:code>')
api.add_resource(WeChatAPPRegisterApi,
                 '/wechat_app/register/<string:code>/<string:phoneCode>')
api.add_resource(PersonalInfoApi,"/personal_info")